package com.puzzlebazar.client.puzzle.control;

import java.util.Iterator;

import com.google.gwt.user.client.Window;
import com.puzzlebazar.client.main.control.GenericController;
import com.puzzlebazar.client.main.control.State;
import com.puzzlebazar.client.main.control.SubControllerImpl;
import com.puzzlebazar.client.puzzle.model.History;
import com.puzzlebazar.client.puzzle.model.HistoryMove;
import com.puzzlebazar.client.puzzle.model.Move;
import com.puzzlebazar.client.puzzle.model.MoveTimer;
import com.puzzlebazar.client.puzzle.view.ExtPuzzleView;
import com.puzzlebazar.client.puzzle.view.MessageDialog;
import com.puzzlebazar.client.puzzle.view.RetimeDialog;
import com.puzzlebazar.client.puzzle.view.Toolbar;
import com.puzzlebazar.client.puzzle.view.HistoryView.HistoryViewInfo;
import com.puzzlebazar.client.squaregrid.model.SGModel;
import com.puzzlebazar.client.squaregrid.view.ComponentHighlighter;
import com.puzzlebazar.client.squaregrid.view.SizeDialog;
import com.puzzlebazar.client.user.UserModel;
import com.puzzlebazar.client.util.ConcurrentVector;
import com.puzzlebazar.client.util.ConnectionLock;
import com.puzzlebazar.client.util.Executable;
import com.puzzlebazar.client.util.Observable;
import com.puzzlebazar.client.util.ObserverTool;
import com.puzzlebazar.client.util.Tool;
import com.puzzlebazar.client.util.Vec2i;

public abstract class PuzzleController extends SubControllerImpl {

	protected final History history;
	protected final ExtPuzzleView view;
	protected final MoveTimer moveTimer;

	private final ConcurrentVector<PuzzleCallback> callbacks = new ConcurrentVector<PuzzleCallback>();

	private final ConnectionLock saveLock = new ConnectionLock(
			"Saving...");

	protected final Tool editTool = new Tool("Edit") {
		@Override
		public void execute() {
			edit();
		}
	};
	protected final Tool playTool = new Tool("Play") {
		@Override
		public void execute() {
			play();
		}
	};
	protected final Tool resizeTool = new Tool("Resize") {
		@Override
		public void execute() {
			resize();
		}
	};
	protected final Tool undoTool;
	protected final Tool redoTool;
	protected final Tool snapToPrevTool;
	protected final Tool clearTool = new Tool("Clear") {
		@Override
		public void execute() {
			if( Window.confirm( "Clear this puzzle, this cannot be undone?" ) )
				clear();
		}
	};
	protected final Tool verifyTool = new Tool("Verify") {
		@Override
		public void execute() {
			verify();
		}
	};
	protected final Tool checkSolutionTool = new Tool("Check") {
		@Override
		public void execute() {
			checkSolutionAndSave();
		}
	};
	protected final Tool messageTool = new Tool("Message") {
		@Override
		public void execute() {
			createOrEditMessage();
		}
	};
	protected final Tool explodeNodeTool;
	protected final Tool deleteNodeTool;	
	protected final Tool cropTool = new Tool("Crop") {
		@Override
		public void execute() {
			crop();
		}

	};
	protected final Tool retimeTool = new Tool("Retime") {
		@Override
		public void execute() {
			retime();
		}

	};
	protected final Tool zoomOffTool = new Tool("Zoom Off") {
		@Override
		public void execute() {
			zoomOff();
		}

	};
	protected final Tool historyHelpTool = new Tool("Help") {
		@Override
		public void execute() {
			historyHelp();
		}

	};
	protected final Tool savePuzzleTool;
	protected final Tool savePlayHistoryTool;
	protected final Tool saveTutorialTool;
	protected final Tool exitTool = new Tool("Exit") {
		@Override
		public void execute() {
			exit();
		}
	};

	/**
	 * Creates a controller for puzzle playing and editing
	 * 
	 * @param model            The associated model
	 * @param history          The associated history
	 * @param moveTimer        The move timer
	 * @param view             The view for the puzzle
	 * @param parentController The parent of this subcontroller
	 */
	public PuzzleController( final SGModel model, final History history,
			MoveTimer moveTimer, ExtPuzzleView view,
			GenericController parentController) {
		super(parentController);

		this.history = history;
		this.moveTimer = moveTimer;
		this.view = view;

		if (history == null) {
			
			undoTool = new Tool("Undo") {
				@Override
				public void execute() {
				}
			};
			redoTool = new Tool("Redo") {
				@Override
				public void execute() {
				}
			};
			snapToPrevTool = new Tool("Snap") {
				@Override
				public void execute() {
				}
			};
			deleteNodeTool = new Tool("Delete") {
				@Override
				public void execute() {
				}
			};
			explodeNodeTool = new Tool("Explode") {
				@Override
				public void execute() {
				}
			};
			undoTool.setEnabled(false);
			redoTool.setEnabled(false);
			snapToPrevTool.setEnabled(false);
			deleteNodeTool.setEnabled(false);
			explodeNodeTool.setEnabled(false);
		} else {
			undoTool = new ObserverTool("Undo", history) {
				@Override
				public void execute() {
					undo();
				}

				@Override
				public void update(Observable observable, Object arg) {
					assert (observable == history);
					setInternalEnabled(history.canUndo());
				}
			};

			redoTool = new ObserverTool("Redo", history) {
				@Override
				public void execute() {
					redo();
				}

				@Override
				public void update(Observable observable, Object arg) {
					assert (observable == history);
					setInternalEnabled(history.canRedo());
				}
			};
			
			snapToPrevTool = new ObserverTool("Snap", history) {
				@Override
				public void execute() {
					snapToPreviousMove();
				}

				@Override
				public void update(Observable observable, Object arg) {
					assert (observable == history);
					setInternalEnabled(history.canUndo());
				}
			};
			
			deleteNodeTool = new ObserverTool("Delete", history) {
				@Override
				public void execute() {
					deleteNode();
				}

				@Override
				public void update(Observable observable, Object arg) {
					assert (observable == history);
					setInternalEnabled(history.isOnMove());
				}
			};
			

			explodeNodeTool = new ObserverTool("Explode", history) {
				@Override
				public void execute() {
					explodeNode();
				}

				@Override
				public void update(Observable observable, Object arg) {
					assert (observable == history);
					setInternalEnabled(history.isOnExplodableMove());
				}
			};
		}
		
		savePuzzleTool = new ObserverTool("Save", model) {
			@Override
			public void execute() {
				savePuzzle();
			}

			@Override
			public void update(Observable observable, Object arg) {
				assert (observable == model);
				setInternalEnabled(!model.isSaved());
			}
		};
		savePlayHistoryTool = new ObserverTool("Save", history) {
			@Override
			public void execute() {
				savePlayHistory();
			}

			@Override
			public void update(Observable observable, Object arg) {
				assert (observable == history);
				setInternalEnabled(!history.isSaved());
			}
		};
		saveTutorialTool = new ObserverTool("Save", history) {
			@Override
			public void execute() {
				saveTutorial();
			}

			@Override
			public void update(Observable observable, Object arg) {
				assert (observable == history);
				setInternalEnabled(!history.isSaved());
			}
		};

		saveLock.addControlledTool(savePlayHistoryTool);
		saveLock.addControlledTool(savePuzzleTool);
		saveLock.addControlledTool(savePuzzleTool);
		saveLock.addControlledTool(checkSolutionTool);
		saveLock.addControlledTool(exitTool);
	}

	@Override
	public void gotoDefaultState() {
		// Default state is the null state
		if (!leaveCurrentState())
			return;
	}

	@Override
	public void release() {
		super.release();
		callbacks.clear();
	}

	@Override
	protected void enterState(State newState) {
		super.enterState(newState);
	}

	@Override
	protected boolean leaveCurrentState() {
		if (!super.leaveCurrentState())
			return false;
		return true;
	}

	/**
	 * Get the attached model
	 * 
	 * @return The attached heyawake model
	 */
	protected abstract SGModel getModel();
	
	/**
	 * Creates all the buttons that should populate a default puzzle edition
	 * toolbar. This method is meant to be used as a shortcut by subclasses, so
	 * that they do not have to individually call addButton() for each standard
	 * button.
	 */
	protected void createDefaultEditPuzzleToolbar() {

		Toolbar result = new Toolbar();
		result.add(editTool);
		result.add(playTool);
		result.add(resizeTool);
		result.add(undoTool);
		result.add(redoTool);
		result.add(clearTool);
		result.add(verifyTool);
		result.add(savePuzzleTool);
		result.add(exitTool);

		view.addToolbar(result);
	}

	/**
	 * Creates all the buttons that should populate a default tutorial edition
	 * toolbar. This method is meant to be used as a shortcut by subclasses, so
	 * that they do not have to individually call addButton() for each standard
	 * button.
	 */
	protected void createDefaultEditTutorialToolbar() {

		Toolbar resultMain = new Toolbar();
		Toolbar resultHistory = new Toolbar();
		resultMain.add(editTool);
		resultMain.add(playTool);
		resultMain.add(resizeTool);
		resultMain.add(clearTool);
		resultMain.add(verifyTool);
		resultMain.add(saveTutorialTool);
		resultMain.add(exitTool);

		resultHistory.add(snapToPrevTool);
		resultHistory.add(messageTool);
		resultHistory.add(deleteNodeTool);
		resultHistory.add(explodeNodeTool);
		resultHistory.add(cropTool);
		resultHistory.add(retimeTool);
		resultHistory.add(zoomOffTool);
		resultHistory.add(historyHelpTool);
		
		view.addToolbar(resultMain);
		view.addHistoryToolbar(resultHistory);
	}

	/**
	 * Creates all the buttons that should populate a default play toolbar. This
	 * method is meant to be used as a shortcut by subclasses, so that they do
	 * not have to individually call addButton() for each standard button.
	 */
	protected void createDefaultPlayToolbar() {
		Toolbar result = new Toolbar();
		result.add(undoTool);
		result.add(redoTool);
		result.add(clearTool);
		result.add(checkSolutionTool);
		if (UserModel.get().isLoggedIn())
			result.add(savePlayHistoryTool);
		result.add(exitTool);
		view.addToolbar(result);
	}

	/**
	 * Creates all the buttons that should populate a default play toolbar. This
	 * method is meant to be used as a shortcut by subclasses, so that they do
	 * not have to individually call addButton() for each standard button.
	 */
	protected void createDefaultViewToolbar() {
		Toolbar result = new Toolbar();
		result.add(exitTool);
		view.addToolbar(result);
	}

	/**
	 * Allows enabling/disabling the edit tool
	 * 
	 * @param enabled
	 *            True to enable the tool, false to disable it
	 */
	public void enableEdit(boolean enabled) {
		editTool.setEnabled(enabled);
	}

	/**
	 * Allows enabling/disabling the play tool
	 * 
	 * @param enabled
	 *            True to enable the tool, false to disable it
	 */
	public void enablePlay(boolean enabled) {
		playTool.setEnabled(enabled);
	}

	/**
	 * Allows enabling/disabling the resize tool
	 * 
	 * @param enabled
	 *            True to enable the tool, false to disable it
	 */
	public void enableResize(boolean enabled) {
		resizeTool.setEnabled(enabled);
	}

	/**
	 * Allows enabling/disabling the verify tool
	 * 
	 * @param enabled
	 *            True to enable the tool, false to disable it
	 */
	public void enableVerify(boolean enabled) {
		verifyTool.setEnabled(enabled);
	}

	/**
	 * Switch to puzzle edition.
	 */
	protected abstract void edit();

	/**
	 * Switch to puzzle playing.
	 */
	protected abstract void play();

	/**
	 * Resize the puzzle, via a dialog box
	 */
	protected void resize() {
		createResizeDialog();		
	}

	/**
	 * Creates a new message move, via a dialog box
	 */
	protected void createOrEditMessage() {
		if(history.isOnMessageMove()) {
			createEditMessageDialog();
		}
		else
			createNewMessageDialog();
	}

	/**
	 * Verify the validity of the puzzle, do not save play history.
	 */
	protected abstract void verify();

	/**
	 * Clear the puzzle.
	 */
	protected abstract void clear();

	/**
	 * Saves the puzzles by calling registered callbacks.
	 */
	private final void savePuzzle() {
		if (saveLock.locked())
			return;
		prepareSavePuzzle();
		executeSavePuzzle();
	}

	/**
	 * Method called just before the puzzle is saved The controller should make
	 * sure it returns to a valid state for saving.
	 */
	protected abstract void prepareSavePuzzle();

	/**
	 * Saves the puzzles playing history by calling registered callbacks.
	 */
	private final void savePlayHistory() {
		if (saveLock.locked())
			return;
		prepareSavePlayHistory();
		executeSavePlayHistory();
	}

	/**
	 * Method called just before the play history is saved The controller should
	 * make sure it returns to a valid state for saving.
	 */
	protected abstract void prepareSavePlayHistory();

	/**
	 * Saves the puzzles by calling registered callbacks.
	 */
	private final void saveTutorial() {
		if (saveLock.locked())
			return;
		prepareSaveTutorial();
		executeSaveTutorial();
	}

	/**
	 * Method called just before the puzzle is saved The controller should make
	 * sure it returns to a valid state for saving.
	 */
	protected abstract void prepareSaveTutorial();

	/**
	 * Discard the puzzles by calling registered callbacks.
	 */
	private final void exit() {
		prepareExit();
		executeExit();
	}

	/**
	 * Method called just before the controller exits.
	 */
	protected abstract void prepareExit();

	/**
	 * Checks the solution of the puzzle by calling registered callbacks. Save
	 * the puzzle if the solution match (hence the lock)
	 */
	private final void checkSolutionAndSave() {
		if (saveLock.locked())
			return;
		executeCheckSolutionAndSave();
	}

	/**
	 * Switch to the state to start the editing process for a puzzle
	 */
	public void startEditPuzzle() {
		view.setPuzzleVisible(true);
		createDefaultEditPuzzleToolbar();
		view.hideHistory();
	}

	/**
	 * Switch to the state to start the editing process for a tutorial
	 */
	public void startEditTutorial() {
		view.setPuzzleVisible(true);
		view.showEditableHistory();
		createDefaultEditTutorialToolbar();
	}

	/**
	 * Switch to the state to start playing
	 */
	public void startPlayPuzzle() {
		moveTimer.start();
		view.setPuzzleVisible(true);
		createDefaultPlayToolbar();
		view.hideHistory();
		moveTimer.notifyObservers();
	}

	/**
	 * Switch to the state to start viewing a puzzle solution
	 */
	public void startViewSolution() {
		view.setPuzzleVisible(true);
		createDefaultViewToolbar();
		view.showHistory();
	}

	/**
	 * Switch to the state to start viewing a tutorial
	 */
	public void startViewTutorial() {
		view.setPuzzleVisible(true);
		createDefaultViewToolbar();
		view.showHistory();
	}
	
	/**
	 * Adds a new callback to be executed when the user requests to save the
	 * current puzzle
	 * 
	 * @param callback
	 *            The callback to add
	 */
	public void addCallback(PuzzleCallback callback) {
		callbacks.add(callback);
	}

	/**
	 * Remove a callback added with addCallback()
	 * 
	 * @param callback
	 *            The callback to remove
	 */
	public void removeCallback(PuzzleCallback callback) {
		callbacks.remove(callback);
	}

	public interface PuzzleCallback {
		/**
		 * Called whenever the user requests that the puzzle be saved
		 * 
		 * @param lock
		 *            The lock object to reset once the puzzle is saved
		 */
		void savePuzzle(ConnectionLock lock);

		/**
		 * Called whenever the user requests that the puzzle be discarded
		 */
		void exit();

		/**
		 * Called whenever the user requests that the history be saved
		 * 
		 * @param lock
		 *            The lock object to reset once the puzzle history is saved
		 */
		void savePlayHistory(ConnectionLock lock);

		/**
		 * Called whenever the user requests that the tutorial to be saved
		 * 
		 * @param lock
		 *            The lock object to reset once the puzzle history is saved
		 */
		void saveTutorial(ConnectionLock lock);

		/**
		 * Called whenever the user requests that the puzzle be checked against
		 * the known solution The puzzle will be saved if it matches (hence the
		 * connection lock)
		 * 
		 * @param lock
		 *            The lock object to reset once the puzzle history is saved
		 */
		void checkSolutionAndSave(ConnectionLock lock);
	}

	/**
	 * Execute all callbacks to save a new puzzle
	 */
	private void executeSavePuzzle() {
		for (Iterator<PuzzleCallback> iterator = callbacks.iterator(); iterator
				.hasNext();) {
			PuzzleCallback callback = iterator.next();
			callback.savePuzzle(saveLock);
		}
	}

	/**
	 * Execute all callbacks to save the history
	 */
	private void executeSavePlayHistory() {
		for (Iterator<PuzzleCallback> iterator = callbacks.iterator(); iterator
				.hasNext();) {
			PuzzleCallback callback = iterator.next();
			callback.savePlayHistory(saveLock);
		}
	}

	/**
	 * Execute all callbacks to save a new puzzle
	 */
	private void executeSaveTutorial() {
		for (Iterator<PuzzleCallback> iterator = callbacks.iterator(); iterator
				.hasNext();) {
			PuzzleCallback callback = iterator.next();
			callback.saveTutorial(saveLock);
		}
	}

	/**
	 * Execute all callbacks to discard the puzzle
	 */
	private void executeExit() {
		for (Iterator<PuzzleCallback> iterator = callbacks.iterator(); iterator
				.hasNext();) {
			PuzzleCallback callback = iterator.next();
			callback.exit();
		}
	}

	/**
	 * Execute all callbacks to check the puzzle solution
	 */
	private void executeCheckSolutionAndSave() {
		for (Iterator<PuzzleCallback> iterator = callbacks.iterator(); iterator
				.hasNext();) {
			PuzzleCallback callback = iterator.next();
			callback.checkSolutionAndSave(saveLock);
		}
	}

	/**
	 * Checks that a solution is valid and optionally highlights invalid
	 * components in the puzzle
	 * 
	 * @param model
	 *            The model to use for verification
	 * @param componentHighlighter
	 *            The object to highlight invalid components (null for no
	 *            highlighting)
	 * @return True if the solution is valid, false otherwise
	 */
	protected boolean isSolutionValid(SGModel model,
			final ComponentHighlighter componentHighlighter) {

		final State previousState = currentState;
		leaveCurrentStateForced();

		view.addTempButton( "Continue", new Executable(){
			@Override
			public void execute() {
				componentHighlighter.unhilightAll();
				enterState(previousState);
				view.clearText();
			}
		});
		

		boolean isValid = model.isSolutionValid(componentHighlighter, view);

		if (isValid)
			view.setText("Solution is valid.");

		return isValid;
	}

	/**
	 * Undo last move
	 */
	private void undo() {
		try {
			HistoryMove historyMove = history.undo(getModel());
			getModel().notifyObservers(historyMove.getPuzzleMove());
			history.notifyObservers(historyMove);
		} catch (Exception exception) {
			exception.printStackTrace();
		}
	}

	/**
	 * Redo last move
	 */
	private void redo() {
		try {
			HistoryMove historyMove = history.redo(getModel());
			getModel().notifyObservers(historyMove.getPuzzleMove());
			history.notifyObservers(historyMove);
		} catch (Exception exception) {
			exception.printStackTrace();
		}
	}


	/**
	 * Snap to previous move (do not undo it)
	 */
	private void snapToPreviousMove() {
		try {
			HistoryMove historyMove = history.snapToPreviousMove();
			history.notifyObservers(historyMove);
		} catch (Exception exception) {
			exception.printStackTrace();
		}
	}

	private void crop() {
		if( history.getCurrentTime() < history.getLastMoveTime() ) {
			if( !Window.confirm( "Cropping the history at this point will delete some move, proceed anyway?" ) )
				return;
		}
		
		Move move = history.crop();
		history.notifyObservers(move);
	}

	private void retime() {
		createRetimeDialog();
	}

	private void zoomOff() {
		HistoryViewInfo historyViewInfo = view.getHistoryViewInfo();
		historyViewInfo.setZoom(0);
		historyViewInfo.setPan(0);
		historyViewInfo.notifyObservers();
	}
	
	private void historyHelp() {
		Window.alert( "Click anywhere on the time bar to move the time marker.\n" +
				"Double-click on a node to move the time marker and select the node.\n" + 
				"Click and drag nodes to change the move timings.\n" +
				"Move two nodes together to merge them in a composite node.\n" +
				"Select a composite node and click \"Explode\" to get the basic moves.\n" +
				"Click \"Crop\" to trim the sequence from the marker to the end.\n" +
				"Click \"Message\" to create a message or edit the selected one.\n" );
	}

	private void deleteNode() {
		try {
			HistoryMove historyMove = history.deleteMoveFromHistory(getModel());
			if( historyMove == null ) {
				Window.alert( "Deleting node affects future moves. Manually clean-up future move or crop history at that point." );
				return;
			}
			getModel().notifyObservers(historyMove.getPuzzleMove());
			history.notifyObservers(historyMove);
		} catch (Exception exception) {
			exception.printStackTrace();
		}
	}
	
	private void explodeNode() {
		try {
			Move move = history.getCurrentMove();
			if( move == null )
				return;
			history.explodeMove( move );
			HistoryMove historyMove = history.mergeOverlappingMoves( getModel() );
			history.notifyObservers( historyMove );
			getModel().notifyObservers( historyMove.getPuzzleMove() );
		} catch (Exception exception) {
			exception.printStackTrace();
		}
	}
	
	/**
	 * Creates a dialog that can be used to resize the model, changing the number of rows and column.
	 */
	private void createResizeDialog() {
		
		try {
			SizeDialog sizeDialog;
			sizeDialog = new SizeDialog( 
					getModel().getSize().x, 
					getModel().getSize().y,
					getModel().getBoundInfo(),
					new SizeDialog.Callback() {
						@Override
						public void ok(int width, int height) 
						{									
							try {
								Move move = getModel().resize( new Vec2i(width, height) );
								HistoryMove historyMove = history.clear( move );
								getModel().notifyObservers(move);
								history.notifyObservers(historyMove);
							} catch (Exception exception) {
								exception.printStackTrace();
							}
						}

						@Override
						public void cancel() {
						}
					});
			sizeDialog.center();
			sizeDialog.show();
		} catch (Exception exception) {
			exception.printStackTrace();
		}				
	
	}


	/**
	 * Creates a dialog that can be used to specify a new message
	 */
	private void createNewMessageDialog() {
		
		try {
			MessageDialog messageDialog = new MessageDialog( 
					new MessageDialog.Callback() {
						@Override
						public void ok( String message ) 
						{									
							try {
								HistoryMove historyMove = history.addMoveToHistory( getModel().setMessage( message, moveTimer.peekTime() ), getModel() );
								if( historyMove != null ) {
									getModel().notifyObservers( historyMove.getPuzzleMove() );
									history.notifyObservers( historyMove );
									moveTimer.step();
									moveTimer.notifyObservers();
								}
							} catch (Exception exception) {
								exception.printStackTrace();
							}
						}

						@Override
						public void cancel() {
						}
					});
			messageDialog.center();
			messageDialog.show();
		} catch (Exception exception) {
			exception.printStackTrace();
		}				
	
	}
	
	

	/**
	 * Creates a dialog that can be used to specify the message attached to the current history time
	 */
	private void createEditMessageDialog() {
		
		final int currentHistoryMoveIndex = history.getCurrentMoveIndex();
		
		try {
			String oldMessage = history.getMessageAtMove(currentHistoryMoveIndex);
			if( oldMessage == null )
				return;
			
			MessageDialog messageDialog = new MessageDialog( 
					new MessageDialog.Callback() {
						@Override
						public void ok( String message ) 
						{									
							try {
								HistoryMove historyMove = history.changeMessageAtMove( currentHistoryMoveIndex, message, getModel() );
								if( historyMove != null ) {
									getModel().notifyObservers( historyMove.getPuzzleMove() );
									history.notifyObservers( historyMove );
									moveTimer.notifyObservers();
								}
							} catch (Exception exception) {
								exception.printStackTrace();
							}
						}

						@Override
						public void cancel() {
						}
					});
			messageDialog.setMessage( oldMessage );
			messageDialog.center();
			messageDialog.show();
		} catch (Exception exception) {
			exception.printStackTrace();
		}				
	
	}	
	
	


	/**
	 * Creates a dialog that can be used to specify a new message
	 */
	private void createRetimeDialog() {
		
		try {
			RetimeDialog retimeDialog = new RetimeDialog( 
					new RetimeDialog.Callback() {
						@Override
						public void ok( long time ) 
						{									
							try {
								history.retime( time );
								HistoryMove historyMove = history.mergeOverlappingMoves( getModel() );
								getModel().notifyObservers( historyMove.getPuzzleMove() );
								history.notifyObservers( historyMove );
							} catch (Exception exception) {
								exception.printStackTrace();
							}
						}

						@Override
						public void cancel() {
						}
					});
			retimeDialog.setTime( history.getDuration() );
			retimeDialog.center();
			retimeDialog.show();
		} catch (Exception exception) {
			exception.printStackTrace();
		}				
	
	}
		
	
}
